﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ServiceProcess;
using System.Configuration;
using System.Net;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace ESBSetup {
    static class Program {

        const string REQUIRED_SERVICES = "services.required";

        static bool isInstall;
        static bool isCleanup;
        static List<string> directories = new List<string>();
        static List<string> requiredServices = new List<string>();
        static string applicationName = ConfigurationManager.AppSettings["applicationName"];
        static object lockObject = new object();

        static void Main(string[] args) {
            if (args.Length < 1) return;
            isInstall = args[0] == "install";
            isCleanup = args.Contains("cleanup");
            Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            var dirInfo = new DirectoryInfo(Environment.CurrentDirectory);
            directories = dirInfo.GetDirectories().Select(dir => dir.FullName.Replace("\\", "/")).ToList();

            if (File.Exists(REQUIRED_SERVICES))
                requiredServices.AddRange(File.ReadAllText(REQUIRED_SERVICES).Split(','));

            if (isInstall) Install();
            else if (args.Contains("setupbackplane"))
                SetupBackplane(args);
            else UnInstall();
        }

        static void SetupBackplane(string[] args) {

            var folder = new DirectoryInfo(Environment.CurrentDirectory);

            var defaultSettingFile = folder.GetFiles("*.config", SearchOption.AllDirectories).First(x => x.Directory.Name == "ESB").FullName;

            var settingXml = File.ReadAllText(defaultSettingFile);

            var currentName = Regex.Match(settingXml, "filename=\"(?<Name>[^\"]+)\"").Groups["Name"].Value.Split('.')[1].ToLower();

            var selectedName = args[1].ToLower();

            foreach (var file in Directory.GetFiles(Environment.CurrentDirectory, "*.config", SearchOption.AllDirectories)) {
                var xml = File.ReadAllText(file);
                xml = xml.Replace(String.Format("app.{0}.xml", currentName), String.Format("app.{0}.xml", selectedName));
                File.WriteAllText(file, xml);
            }

            foreach (var file in Directory.GetFiles(Environment.CurrentDirectory, "*configurations.xml", SearchOption.AllDirectories)) {
                var xml = File.ReadAllText(file);
                xml = xml.Replace(String.Format("configurations.{0}.xml", currentName), String.Format("configurations.{0}.xml", selectedName));
                File.WriteAllText(file, xml);
            }

            foreach (var file in Directory.GetFiles(Environment.CurrentDirectory, "*services.xml", SearchOption.AllDirectories)) {
                var xml = File.ReadAllText(file);
                xml = xml.Replace(String.Format("services.{0}.xml", currentName), String.Format("services.{0}.xml", selectedName));
                File.WriteAllText(file, xml);
            }

            if (args.Length > 2) {
                File.WriteAllText(REQUIRED_SERVICES, String.Join(" ", args.Skip(2)));
            }
        }

        static List<string> GetServices(string name) {
            name = name.ToLower();
            var isRequired = requiredServices.Any(x => name.Contains(x));
            return ServiceController.GetServices()
                .Where(s => isRequired || (!isRequired && !requiredServices.Any(x => s.ServiceName.ToLower().Contains(x))))
                .Where(s => s.ServiceName.ToLower().Contains(name)).Select(s => s.ServiceName).ToList();
        }

        static void ControlService(string serviceName, ServiceControllerStatus status) {
            try {
                var service = new ServiceController(serviceName);
                if (service == null) return;
                if (service.Status != status) {
                    if (status == ServiceControllerStatus.Stopped) service.Stop();
                    else if (status == ServiceControllerStatus.Running) service.Start();
                }
                service.WaitForStatus(status);
            } catch { }
        }

        static void ExecuteFile(string filename) {
            var fileInfo = new FileInfo(filename);
            ProcessStartInfo info = new ProcessStartInfo(filename);
            info.UseShellExecute = false;
            info.CreateNoWindow = true;
            info.ErrorDialog = false;
            info.WorkingDirectory = fileInfo.DirectoryName;
            info.WindowStyle = ProcessWindowStyle.Hidden;
            var process = Process.Start(info);
            try {
                process.WaitForExit();
            } catch { }
        }

        static void RunBatFiles(string name) {
            directories.ForEach(dir => {
                    var fileName = String.Format("{0}/{1}.bat", dir, name);
                    if (!File.Exists(fileName)) return;
                    ExecuteFile(fileName);
                });
        }

        static void StartService(string serviceName) {
            ControlService(serviceName, ServiceControllerStatus.Running);
        }

        static void StopService(string serviceName) {
            ControlService(serviceName, ServiceControllerStatus.Stopped);
        }

        static void RunBatFiles() {
            RunBatFiles("uninstall");
            RunBatFiles("install");
        }


        static void StopServices() {
            GetServices("pservicebus.servicemonitor").ForEach(s => StopService(s));
            GetServices("pservicebus.").ForEach(s => StopService(s));
            requiredServices.ForEach(serviceName => GetServices(serviceName).ForEach(s => StopService(s)));
        }

        static void StartServices() {
            requiredServices.ForEach(serviceName => GetServices(serviceName).ForEach(s => StartService(s)));
            GetServices("pservicebus.servicemonitor").ForEach(s => StartService(s));
            GetServices("pservicebus.").ForEach(s => StartService(s));
        }

        static void Init() {
            StopServices();
        }

        static void Install() {
            Init();
            Register("install");
            RunBatFiles();
            StartServices();
            File.Delete(REQUIRED_SERVICES);
        }

        static void UnInstall() {
            Init();
            if (!isCleanup)
                Register("uninstall");
            RunBatFiles("uninstall");
        }

        static void Register(string type) {
            try {
                var url =
                    String.Format("http://iomegatrix.com/Registration/service/register/?applicationName={0}&type={1}",
                    applicationName, type);
                var request = WebRequest.Create(url);
                request.Method = "POST";
                request.ContentLength = 0;
                var response = request.GetResponse();
                response.Close();
            } catch { }
        }
    }
}
